﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;

namespace PD.DataAccess
{
    /// <summary>
    /// The main entry point for the LINQ to SQL framework.
    /// </summary>
    public partial class PDDataClassesDataContext
    {
        /// <summary>
        /// Occurs when the invoice is being inserted.
        /// </summary>
        public static event EventHandler<EntityInsertedEventArgs<Invoice>> InvoiceInserted;

        /// <summary>
        /// Occurs when the task is being updated.
        /// </summary>
        public static event EventHandler<EntityUpdatedEventArgs<Task>> TaskUpdated;

        /// <summary>
        /// Gets or sets a value indicating whether the event firing is enabled.
        /// </summary>
        /// <value>
        /// <c>true</c> if the event firing is enabled; otherwise, <c>false</c>.
        /// </value>
        public bool EventFiringEnabled { get; set; }

        /// <summary>
        /// Sends changes that were made to retrieved objects to the underlying database, and specifies the action to be taken if the submission fails.
        /// </summary>
        /// <param name="failureMode">The action to be taken if the submission fails. Valid arguments are as follows:<see cref="F:System.Data.Linq.ConflictMode.FailOnFirstConflict"/><see cref="F:System.Data.Linq.ConflictMode.ContinueOnConflict"/></param>
        public override void SubmitChanges(ConflictMode failureMode)
        {
            ChangeSet changeSet = this.GetChangeSet();
            base.SubmitChanges(failureMode);

            if (this.EventFiringEnabled)
            {
                // raise invoice inserted
                this.RaiseInsertedEvent<Invoice>(changeSet.Inserts.Cast<EntityBase>(), InvoiceInserted);

                // raise task updated
                this.RaiseUpdatedEvent<Task>(this.Tasks, changeSet.Updates.Cast<EntityBase>(), TaskUpdated);
            }
        }

        /// <summary>
        /// Called when the instance is created.
        /// </summary>
        partial void OnCreated()
        {
            this.EventFiringEnabled = true;
        }

        /// <summary>
        /// Raises the inserted event.
        /// </summary>
        /// <typeparam name="T">Type of inserted entity.</typeparam>
        /// <param name="changeSetEntities">A list of entities that have been inserted into the System.Data.Linq.ChangeSet.</param>
        /// <param name="handler">The handler should be invoked.</param>
        private void RaiseInsertedEvent<T>(IEnumerable<EntityBase> changeSetEntities, EventHandler<EntityInsertedEventArgs<T>> handler) where T : EntityBase
        {
            if (handler != null)
            {
                IEnumerable<T> entities = changeSetEntities.Where(x => x is T).Cast<T>();
                foreach (T entity in entities)
                {
                    handler.Invoke(new object(), new EntityInsertedEventArgs<T>(entity));
                }
            }
        }

        /// <summary>
        /// Raises the updated event.
        /// </summary>
        /// <typeparam name="T">Type of updated entity.</typeparam>
        /// <param name="table">The entities table.</param>
        /// <param name="changeSetEntities">A list of entities that have been updated into the System.Data.Linq.ChangeSet.</param>
        /// <param name="handler">The handler should be invoked.</param>
        private void RaiseUpdatedEvent<T>(Table<T> table, IEnumerable<EntityBase> changeSetEntities, EventHandler<EntityUpdatedEventArgs<T>> handler) where T : EntityBase
        {
            if (handler != null)
            {
                IEnumerable<T> entities = changeSetEntities.Where(x => x is T).Cast<T>();
                foreach (T entity in entities)
                {
                    handler.Invoke(new object(), new EntityUpdatedEventArgs<T>(table.GetModifiedMembers(entity), entity));
                }
            }
        }
    }
}
